文章目录
  1. 1. 某渣的凭印象回(hu)顾(zhou)
  2. 2. Binder的设计思想/工作原理
  3. 3. Binder实践
    1. 3.1. Service的启动过程
    2. 3.2. Binder驱动的实现
      1. 3.2.1. 调用mRemote.transact时进到了BinderProxy并在其中调用native方法android_os_BinderProxy_transact()
      2. 3.2.2. jni中的target->transact调用进到BpBinder, 再进到IPCThreadState
      3. 3.2.3. IPCThreadState::waitForResponse() 在一个 while 循环里不断的调用 talkWithDriver() 并检查是否有数据返回
      4. 3.2.4. IPCThreadState::talkWithDriver() 函数是真正与 binder 驱动交互的实现
      5. 3.2.5. IPCThreadState::executeCommand(int32_t cmd) 处理返回命令
      6. 3.2.6. Binder设备驱动实现
  4. 4. 结语

某渣的凭印象回(hu)顾(zhou)

Binder是Android提供的一种RPC机制, 它是C/S架构, 可以远程调用服务, 调用其他进程甚至其他App的服务. 它利用AIDL描述服务接口, 通过bind和unbind绑定和解绑具体服务, 其内部使用代理完成服务功能的调用. 调用方需要知道AIDL, 被调用方需要实现AIDL. Android系统的服务就是通过Binder机制来使用的.

Binder的设计思想/工作原理

Binder是一种进程间通讯的机制, 不同于Handler的线程间通讯, 由于进程间没有共享区域, 所以Handler那种消息队列的机制在进程之间进行就会变得比较麻烦(进程A将消息拷贝到内核缓存空间, 另一进程B从内核缓存空间取消息), 特别是当进程间通讯涉及到接口调用等业务流程时. 出于安全性考虑, 一个进程的空间只对进程内部开放, 外部想要访问进程内的数据, 就只能曲线救国. Binder就是其中一种方式.

Binder是一种特化的AIDL服务, 换句话说, AIDL是对Binder机制的上层封装, 它可以快速实现进程间通讯, 所以要想理解Binder就必须理解AIDL. 关于AIDL可以看我的博文AIDL入门, 简单来说, AIDL是服务的接口描述文件, 它在服务端和客户端都共同存在且内容相同, SDK的aidl工具可以帮助我们把.aidl文件转换成同名的.java文件, 只要我们手工调用该工具转换一下, 并看一看转换后的文件, 我相信就能够完全理解aidl的使用原理了(其实跟Hessian之类的RPC框架大同小异). 具体到Binder, 我们可以去看看Binder的实现源码和Binder驱动的源码, 说白了就是系统为我们实现了一套基于Binder接口的获取/绑定/解绑/释放服务代理的业务逻辑, 我们只需要负责将具体的服务传给Binder就可以了. 如果没有Binder, 进行进程间通讯就必须要自己实现基于AIDL的业务逻辑, 实际上这样也是行得通的, 只不过系统服务都是基于Binder实现的, 所以我们有必要了解Binder的实现原理.
在最下层, Binder驱动通过Native代码实现, 它是Binder接口的最终实现, 关于Binder驱动的源码可以看这篇博客Binder 源码分析, 尤其是其代码注释.

在Linux中有很多进程间通讯的方式, 为什么Android唯独自己实现了一个Binder机制? 我认为主要原因是现有的Linux进程间通讯方式都太”重”了, 含有许多虽然好但是在Android环境下并不实用的特性. 可以明确的是, 现有的进程间通讯方式肯定可以应用在Android这个基于Linux系统内核的操作系统上. 相比之下, Binder的设计使得它只进行一次数据拷贝, 传输更加高效, 而且发送方和接收方都互相知道对方身份, 更加安全.

Binder实践

依旧, 如果只想用Binder, 那直接继承它并实现相应接口即可, 这里的实践指的是看Binder源码. 默认大家已经看过并理解了AIDL的相关内容.
不同于上层Framework, 这里要理解Binder需要涉及到底层native代码, 所以我们要提前准备好Android系统源码, 当然前面看Java层代码时不需要. 这里我以4.0源码为基础.
照惯例我们先从Binder源码看起. 打开frameworks/base/core/java/android/os/Binder.java, 先来看看它都有哪些主要内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
注释, 大意是说这个类是一个用于远程调用的基类, 是IBinder中定义的轻量级RPC的核心部分, 提供了远程对象本地实现的标准支持, 多数情况下开发者不需要直接实现Binder类, 而是利用aidl工具描述服务接口, 让aidl自动生成合适的Binder子类, 但是开发这当然可以直接继承Binder来实现自己的RPC协议或者仅仅是实例化一个Binder对象作为token在进程之间共享.
*/
public class Binder implements IBinder{// Binder类实现IBinder接口
private int mObject;
private IInterface mOwner;
private String mDescriptor;

public static final native int getCallingPid();// 调用者进程ID, 可以用来检查权限
public static final native int getCallingUid();// 返回与进程绑定的调用者用户ID, 可以用来检查权限
public static final native long clearCallingIdentity();// 重置调用者ID, 当你需要调用别的Interface的时候, 为了让被调用的Interface检查你自己的权限, 你需要重置调用者ID. 它返回的token可以通过下面这个方法恢复调用者ID
public static final native void restoreCallingIdentity(long token);// 恢复调用者ID
public static final native void setThreadStrictModePolicy(int policyMask);// 设置native层StrictMode策略
public static final native int getThreadStrictModePolicy();// 获取native层StrictMode策略
public static final native void flushPendingCommands();// 把等待中的命令刷到内核驱动. 如果将要执行一个可能阻塞很长时间的命令, 那么本方法可以将线程中等待的命令刷到内核驱动, 以防止本线程过久地持有等待中命令的引用
public static final native void joinThreadPool();// 把调用者线程加入IPC线程池, 该方法仅在进程退出时返回

public Binder() {
init();// native method
// code to check potential leaks
}
public void attachInterface(IInterface owner, String descriptor);// 绑定IInterface和对应的descriptor
public String getInterfaceDescriptor();
public boolean pingBinder();// 默认返回true
public boolean isBinderAlive();// 默认返回true
public IInterface queryLocalInterface(String descriptor);// 返回descriptor对应的IInterface或者null
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags);// 真正的事务执行函数, 希望子类重写
public final boolean transact(int code, Parcel data, Parcel reply, int flags);// 事务执行函数, 里面回调onTransact
private boolean execTransact(int code, int dataObj, int replyObj, int flags);// 回调onTrasact, 如果抛出异常则返回true
public void linkToDeath(DeathRecipient recipient, int flags);// 本地实现无内容
public boolean unlinkToDeath(DeathRecipient recipient, int flags);// 本地实现无内容

private native final void init();
private native final void destroy();
}// Binder类

final class BinderProxy implements IBinder {// BinderProxy类
BinderProxy() {
mSelf = new WeakReference(this);
}

// 以下六个方法都成了native方法
public native boolean pingBinder();
public native boolean isBinderAlive();
public native String getInterfaceDescriptor();
public native boolean transact(int code, Parcel data, Parcel reply, int flags);
public native void linkToDeath(DeathRecipient recipient, int flags);
public native boolean unlinkToDeath(DeathRecipient recipient, int flags);

final private WeakReference mSelf;// 指向自身的弱引用
private int mObject;
private int mOrgue;
}

看完源码至少有三个疑问: 1. IInterface和IBinder定义了哪些接口? 2. BinderProxy是什么, 怎么用的? 3. Binder.java中涉及到的那些native方法, 是怎么实现的?
打开frameworks/base/core/java/android/os/IBinder.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/** 注释中详细讲述了IBinder的设计思路. 核心API是transact(), 与Binder的onTransact成对. 作为本地对象的它发送一个调用到远程IBinder对象, 同时作为远程对象的它可以接受一个调用并放到一个Binder对象中. 这个API是同步的, 以保证仅在远程onTransact返回后, 本地transact才返回, 这是所期望的行为.  
系统在每个进程中维护一个事务线程池, 用于分发所有从外部进程进来的IPC. Binder系统允许递归调用, 比如A调用B, B的onTransact中又调用了A. */
// 定义了用户可以使用的事务代码
int FIRST_CALL_TRANSACTION = 0x00000001;
int LAST_CALL_TRANSACTION = 0x00ffffff;

// IBinder协议的事务代码
int PING_TRANSACTION = ('_'<<24)|('P'<<16)|('N'<<8)|'G';
int DUMP_TRANSACTION = ('_'<<24)|('D'<<16)|('M'<<8)|'P';
int INTERFACE_TRANSACTION = ('_'<<24)|('N'<<16)|('T'<<8)|'F';
int TWEET_TRANSACTION = ('_'<<24)|('T'<<16)|('W'<<8)|'T';
int LIKE_TRANSACTION = ('_'<<24)|('L'<<16)|('I'<<8)|'K';// 告诉app调用者喜欢它. 可选命令, 应用不必处理, 没啥卵用. 默认实现啥也不做.
int SYSPROPS_TRANSACTION = ('_'<<24)|('S'<<16)|('P'<<8)|'R';// hide

// transact的标记, 表示这是一个单向调用, 调用者不等待被调用者的结果, 而是立即返回
int FLAG_ONEWAY = 0x00000001;
public static final int MAX_IPC_SIZE = 64 * 1024;// hide

public String getInterfaceDescriptor();
// 查询Binder是否可用有三种方式, 当Binder不可用时, transact()会抛出RemoteException, pingBinder()会返回false, linkToDeath()预先连接一个DeathRecipient, 不可用时会回调这个DeathRecipient的binderDied()
public boolean pingBinder();
public boolean isBinderAlive();

public IInterface queryLocalInterface(String descriptor);

public boolean transact(int code, Parcel data, Parcel reply, int flags);

public interface DeathRecipient {
public void binderDied();
}
public void linkToDeath(DeathRecipient recipient, int flags);// 连接一个DeathRecipient接收器, 当Binder不可用时回调
public boolean unlinkToDeath(DeathRecipient recipient, int flags);

可见, IBinder定义了一套Transaction协议用于指明发起的Transaction类型, 定义了transact()核心接口, 该接口与Binder中的onTransact配合使用才能完成远程调用的功能. 定义了查询接口, 返回一个IInterface实例. 下面看看这个接口定义:

1
2
3
4
public interface IInterface
{
public IBinder asBinder();
}

就这一个接口方法, 返回IBinder实例. 注释中说该方法返回与该Interface绑定的Binder实例.
以上这些内容, 定义了一个基本的Binder系统框架, 即通过同一套Binder & IBinder & IInterface接口, 本地以transact()发起远程调用, 远程在onTransact()中处理相应调用. 本地以asInterface()获取远程服务的实例(实际获得的是服务的代理, 代理内对每个服务接口中的方法, 调用远程服务的transact方法, 传递一个约定好的事务代码和方法参数, 远程服务的onTransact会对每个约定好的事务代码, 生成相应的switch case, 调用真正的服务接口实现. 由于客户端和服务端对服务接口的定义是相同的, 故生成的服务接口也相同, 可以在本地aidl生成的java文件中查看onTransact的实现), 远程以asBinder()返回远程服务的实例, 本地通过asInterface返回的代理来调用远程服务的方法, 跟调用本地服务方法表面上看起来没有差别.

Service的启动过程

离开具体实现的Binder是无法工作的, 我们自己当然可以自行继承Binder来写自己的远程服务. AIDL是Android为我们提供的一种方便快捷生成Binder实现的方式和工具, 而Service是由系统实现了服务端的Binder. 我们以它为例, 说明如何启动服务, 以及其中哪里用到了Binder.
我们知道, 要获取服务(系统服务除外, 其实系统服务就是提供了一个通过descriptor获取服务的接口), 首先我们要知道服务的全名, 在Intent中设定服务全名, 并指定一个ServiceConnection回调, 调用bindService(Intent, ServiceConnection, CONTEXT_OPTION)绑定服务(其中第三个参数的含义稍后解释), 在ServiceConnection中获取到服务实例. 我们已经知道ServiceConnection的回调方法被调用时已经得到了服务实例, 下面我们看看bindService如何绑定服务获取服务实例.
[Android应用程序绑定服务(bindService)的过程源代码分析]: http://blog.csdn.net/luoshengyang/article/details/6745181
bindService方法的定义来自于Context, ActivitybindService调用的是ContextWrapper.bindService, 其默认实现是调用mBase.bindService, mBase是一个Context类型的成员变量, 这里的mBase是一个ContextImpl实例变量. 在ContextImpl.java中, bindService是这么定义的:

class ContextImpl extends Context {
    ......

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {  
        IServiceConnection sd;  
        if (mPackageInfo != null) {  
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),  
                mMainThread.getHandler(), flags);  
        } else {  
            ......  
        }  
        try {  
            int res = ActivityManagerNative.getDefault().bindService(  
                mMainThread.getApplicationThread(), getActivityToken(),  
                service, service.resolveTypeIfNeeded(getContentResolver()),  
                sd, flags);  
            ......  
            return res != 0;  
        } catch (RemoteException e) {  
            return false;  
        }
    }
    ......
}

这里的mMainThread是一个ActivityThread实例, 通过它的getHandler函数可以获得一个Handler对象(这里返回的Handler是在ActivityThread类内部从Handler类继承下来的一个H类实例变量), 有了这个Handler对象后, 就可以把消息分发到ActivityThread所在的线程消息队列中去了.
获得了这个Handler对象后, 就调用mPackageInfo.getServiceDispatcher函数来获得一个IServiceConnection接口, 这里的mPackageInfo的类型是LoadedApk, 它的getServiceDispatcher函数比较长我就不贴了, 大致上它先以传进来的context为key查找mServices成员中是否已经有对应的ServiceDispatcher, 没有则新建一个, 将传进来的ServiceConnection和Handler都保存在ServiceDispatcher内部, 并创建一个InnerConnection, 这是一个Binder对象! 最后返回给sd的就是这个InnerConnection对象.


接着调用ActivityManagerNative.getDefault().bindService(), 在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中, 函数定义如下:

class ActivityManagerProxy implements IActivityManager  
{  
    ......  

    public int bindService(IApplicationThread caller, IBinder token,  
            Intent service, String resolvedType, IServiceConnection connection,  
            int flags) throws RemoteException {  
        Parcel data = Parcel.obtain();  
        Parcel reply = Parcel.obtain();  
        data.writeInterfaceToken(IActivityManager.descriptor);  
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeStrongBinder(token);  
        service.writeToParcel(data, 0);  
        data.writeString(resolvedType);  
        data.writeStrongBinder(connection.asBinder());// 被调用的服务的Binder作为数据传输给服务端
        data.writeInt(flags);  
        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);// 调用了transact, 进Binder驱动
        reply.readException();  
        int res = reply.readInt();  
        data.recycle();  
        reply.recycle();  
        return res;  
    }  

    ......  
}  

这个函数通过Binder驱动程序就进入到ActivityManagerServicebindService函数去了(到此为止, 代码执行就从Binder客户端进入到了Binder服务端), 它的定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中, 代码比较长就不贴了. 主要做了以下这些事:
函数首先根据传进来的参数token(是调用者Activity在ActivityManagerService里面的令牌), 将这个代表调用者Activity的ActivityRecord取回来.
接着通过retrieveServiceLocked函数, 得到一个ServiceRecord, 这个ServiceReocrd描述的是一个Service对象,这是根据传进来的参数service的内容获得的(service是个Intent, 带有我们要用的具体Service的信息).
接着把传进来的connection参数封装成一个ConnectionRecord对象, 并保存了它的一个引用到activity.connections中以方便后续取用.
最后, 传进来的第四个参数flags是有限的几种BindServiceFlags中的一种, 它决定了具体行为. 以BIND_AUTO_CREATE为例, 它会走到private final boolean bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean whileRestarting), 第一个参数就是前面的Intent service, 第二个参数通过service.getFlags()得到, 第三个参数传的false. 该函数中, 首先判断应用进程是否存在, 如果存在则调用realStartServiceLocked(r, app), app是通过进程名和uid获取到的ProcessRecord(如果不存在则启动新进程, 并将服务压栈等待进程启动完成, 在这个新进程上执行serivce). 来看这个函数实现:

public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
    ......
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app) throws RemoteException {  
        ......  
        r.app = app;  
        ......  

        app.services.add(r);
        ......  

        try {  
            ......  
            app.thread.scheduleCreateService(r, r.serviceInfo);  
            ......  
        } finally {  
            ......  
        }  

        requestServiceBindingsLocked(r);  

        ......  
    }
    ......
}

这个函数执行了两个操作, 一个是app.thread.scheduleCreateService(r, r.serviceInfo)在应用程序进程内部创建Service, 这个操作会导致Service的onCreate被调用; 另一个操作是调用requestServiceBindingsLocked函数向服务获取一个Binder对象, 这个操作会导致Service的onBind函数被调用. 可能有读者觉得有点偏题了, 实际不然, 这两个操作都依赖Binder机制. 先来看前者:

class ApplicationThreadProxy implements IApplicationThread {  
    ......  

    public final void scheduleCreateService(IBinder token, ServiceInfo info)  
            throws RemoteException {  
        Parcel data = Parcel.obtain();  
        data.writeInterfaceToken(IApplicationThread.descriptor);  
        data.writeStrongBinder(token);  
        info.writeToParcel(data, 0);  
        mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,  
            IBinder.FLAG_ONEWAY);// 又一次Binder调用, 进入到的是ApplicationThread.scheduleCreateService, flag引人注目
        data.recycle();  
    }  

    ......  
}  

这里通过Binder驱动程序就进入到ApplicationThreadscheduleCreateService函数去了. 它的定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {  
    ......  

    private final class ApplicationThread extends ApplicationThreadNative {  
        ......  

        public final void scheduleCreateService(IBinder token,  
            ServiceInfo info) {  
            CreateServiceData s = new CreateServiceData();  
            s.token = token;  
            s.info = info;  

            queueOrSendMessage(H.CREATE_SERVICE, s);  
        }  

        ......  
    }  
    ......  
}  

其中queueOrSendMessageActivityThread的方法, 它用Handler把创建服务的操作放到了Activity线程的消息队列中, 在handleMessage时调用handleCreateService处理该消息, 代码如下:

public final class ActivityThread {  
    ......  

    private final void handleCreateService(CreateServiceData data) {  
        ......  

        LoadedApk packageInfo = getPackageInfoNoCheck(  
        data.info.applicationInfo);  
        Service service = null;  
        try {  
            java.lang.ClassLoader cl = packageInfo.getClassLoader();  
            service = (Service) cl.loadClass(data.info.name).newInstance();  // 加载类, 获得实例
        } catch (Exception e) {  
            ......  
        }  

        try {  
            ......  

            ContextImpl context = new ContextImpl();  
            context.init(packageInfo, null, this);  

            Application app = packageInfo.makeApplication(false, mInstrumentation);  
            context.setOuterContext(service);  
            service.attach(context, this, data.info.name, data.token, app,  
                ActivityManagerNative.getDefault());  // 绑定服务

            service.onCreate();  // 进入onCreate生命周期
            mServices.put(data.token, service); // 保存服务映射
            ......  
        } catch (Exception e) {  
            ......  
        }  
    }  
    ......  
}  

至此, 服务实例就创建出来了. 下面回到realStartServiceLockedrequestServiceBindingsLocked, 它的定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中:

public final class ActivityManagerService extends ActivityManagerNative  
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
    ......  

    private final void requestServiceBindingsLocked(ServiceRecord r) {  
        Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();  
        while (bindings.hasNext()) {  
            IntentBindRecord i = bindings.next();  
            if (!requestServiceBindingLocked(r, i, false)) {  
                break;  
            }  
        }  
    }  

    private final boolean requestServiceBindingLocked(ServiceRecord r,  
            IntentBindRecord i, boolean rebind) {  
        ......  
        if ((!i.requested || rebind) && i.apps.size() > 0) {  
          try {  
              ......  
              r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);  
              ......  
          } catch (RemoteException e) {  
              ......  
          }  
        }  
        return true;  
    }  

    ......  
}  

(下回分解)
1月9日, 继续分解Service启动过程.
前面说到经过handleCreateService之后, Service实例就通过ClassLoader载入到内存, 并通过newInstance创建了实例, 且进入到onCreate周期. 创建完毕后, 接着调用requestServiceBindingsLocked, 这个方法从名字看应该是要绑定服务了, 打开源码发现它实际调用了app.thread.scheduleBindService, 传的参数ServiceRecord r代表我们启动的自定义服务. app.thread是一个Binder对象的远程接口, 它的类型是ApplicationThreadProxy, 这一点从前面也看得出来. 通过代理和Binder驱动, 我们就进入到ApplicationThreadscheduleBindService中了:

class ApplicationThreadProxy implements IApplicationThread {  
    ......  

    public final void scheduleBindService(IBinder token, Intent intent, boolean rebind)  throws RemoteException {  
        Parcel data = Parcel.obtain();  
        data.writeInterfaceToken(IApplicationThread.descriptor);  
        data.writeStrongBinder(token);  
        intent.writeToParcel(data, 0);  
        data.writeInt(rebind ? 1 : 0);  
        mRemote.transact(SCHEDULE_BIND_SERVICE_TRANSACTION, data, null,  
            IBinder.FLAG_ONEWAY);  
        data.recycle();  
    }  

    ......  
}  

那么, 我们来看看ApplicationThreadscheduleBindService是怎么实现的:

public final class ActivityThread {  
    ......  

    public final void scheduleBindService(IBinder token, Intent intent,  
            boolean rebind) {  
        BindServiceData s = new BindServiceData();  
        s.token = token;  
        s.intent = intent;  
        s.rebind = rebind;  

        queueOrSendMessage(H.BIND_SERVICE, s);  
    }  

    ......  
}  

很眼熟对不对? 相信不用我说你也知道之后是什么了:

switch (msg.what) {  
......  
case BIND_SERVICE:  
    handleBindService((BindServiceData)msg.obj);  
    break;  
......  
}  

...
private final void handleBindService(BindServiceData data) {  
    Service s = mServices.get(data.token);  
    if (s != null) {  
        try {  
            data.intent.setExtrasClassLoader(s.getClassLoader());  
            try {  
                if (!data.rebind) {  
                    IBinder binder = s.onBind(data.intent);  
                    ActivityManagerNative.getDefault().publishService(  
                        data.token, data.intent, binder);  
                } else {  
                    ......  
                }  
                ......  
            } catch (RemoteException ex) {  
            }  
        } catch (Exception e) {  
            ......  
        }  
    }  
}

首先将前面保存在mServices中的服务通过data.token取出来放到本地变量, 然后让它执行onBind获得一个Binder对象, 接着将这个对象传递给ActivityManagerService.getDefa().publishService(). onBind是自定义服务自己重写的, 就是返回一个实现了IBinder接口的Binder对象. publishSerivce 定义在frameworks/base/core/java/android/app/ActivityManagerNative.java中, 如下:

class ActivityManagerProxy implements IActivityManager  
{  
    ......  
    public void publishService(IBinder token,  
    Intent intent, IBinder service) throws RemoteException {  
        Parcel data = Parcel.obtain();  
        Parcel reply = Parcel.obtain();  
        data.writeInterfaceToken(IActivityManager.descriptor);  
        data.writeStrongBinder(token);  
        intent.writeToParcel(data, 0);  
        data.writeStrongBinder(service);  
        mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);// 眼熟不?  
        reply.readException();  
        data.recycle();  
        reply.recycle();  
    }  
    ......  
}  

再来看publishService的实现, 理所当然它的定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中:

public final class ActivityManagerService extends ActivityManagerNative  
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
    ......  

    public void publishService(IBinder token, Intent intent, IBinder service) {  
        ......  
        synchronized(this) {  
            ......  
            ServiceRecord r = (ServiceRecord)token;  
            ......  

            ......  
            if (r != null) {  
                Intent.FilterComparison filter  
                    = new Intent.FilterComparison(intent);  
                IntentBindRecord b = r.bindings.get(filter);  
                if (b != null && !b.received) {  
                    b.binder = service;  
                    b.requested = true;  
                    b.received = true;  
                    if (r.connections.size() > 0) {  
                        Iterator<ArrayList<ConnectionRecord>> it  
                            = r.connections.values().iterator();  
                        while (it.hasNext()) {  
                            ArrayList<ConnectionRecord> clist = it.next();  
                            for (int i=0; i<clist.size(); i++) {  
                                ConnectionRecord c = clist.get(i);  
                                ......  
                                try {  
                                    c.conn.connected(r.name, service);  
                                } catch (Exception e) {  
                                    ......  
                                }  
                            }  
                        }  
                    }  
                }  

                ......  
            }  
        }  
    }  

    ......  
}  

这里传进来的service不出意外的话就是我们自定义onBinder返回的那个东西了, 也就是我们自定义服务的实例. 这里的token是一个ServiceRecord对象, 是在前面bindService中中创建的. 在那里, 我们保存了自定义服务的一个ConnectionRecord在这个ServiceRecord.connections列表中, 因此这里可以通过r.connections取出那个ConnectionRecord.
取出ConnectionRecord之后, 调用成员变量的函数conn.connected(). 这个conn是一个IServiceConnection类型, 它是一个Binder对象的远程接口, 这个Binder对象, 就是我们在前面创建的LoadedApk.ServiceDispatcher.InnerConnection对象. 因此, 这里的connected就到了InnerConnection.connected:

// in file frameworks/base/core/java/android/app/LoadedApk.java
final class LoadedApk {  
    ......  

    static final class ServiceDispatcher {  
        ......  

        private static class InnerConnection extends IServiceConnection.Stub {  
            ......  

            public void connected(ComponentName name, IBinder service) throws RemoteException {  
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();  
                if (sd != null) {  
                    sd.connected(name, service);  // 转到了外层ServiceDispatcher类中的connected
                }  
            }  
            ......  
        }  
        ......  

        public void connected(ComponentName name, IBinder service) {  
            if (mActivityThread != null) {  
                mActivityThread.post(new RunConnection(name, service, 0)); // 放到ActivityThread的消息队列中. mActivityThread是一个Handler实例  
            } else {  
                ......  
            }  
        }  
        ......  

        private final class RunConnection implements Runnable {  
            ......  

            public void run() {  
                if (mCommand == 0) {  
                    doConnected(mName, mService);  
                } else if (mCommand == 1) {  
                    ......  
                }  
            }  
            ......  
        }  
        ......  

        public void doConnected(ComponentName name, IBinder service) {  
            ......  

            // If there is a new service, it is now connected.  
            if (service != null) {  
                mConnection.onServiceConnected(name, service);  
            }  
        }  
    }  
    ......  
}  

新建了一个RunConnection并调用H.post放到了ActivityThread的消息队列中. 当处理该消息时, 会运行的RunConnectionrun()来处理, 原因见我另一篇文章Handler原理. 此时mCommand==0, 最后就会执行到mConnection.onServiceConnected函数. 这里的mConnection的类型是ServiceConnection, 它是在前面设置好的, 它是我们调用bindService时传入的ServiceConnection实例, 在前面我们用它通过ServiceDispatcher换得了一个IServiceConnection对象.
传入的第二个参数service是一个IBinder对象, 它其实就是我们前面从自定义Service中得到的自定义Binder对象, 因此这里我们可以直接强转成那个自定义Binder类型, 并通过它的getService接口获取到自定义服务的接口. 至此, 我们经过onServiceConnection, 调用getService, 绑定并获取了自定义服务.

Binder驱动的实现

上面多次提到”进入了Binder驱动”, 可见Binder驱动在这个设计中具有重要的桥梁作用. 那么除了上面看到的那些, Binder驱动到底是什么样子呢? 接下来让我们深入Binder驱动源码.
首先我们要知道是哪里进入到Native Binder驱动的:
IYourService.Stub.Proxy.YOUR_API()中, 调用android.os.IBinder(实现在 android.os.Binder.BinderProxy).transact()发送Stub.TRANSACTION_YOUR_API ==> BinderProxy.transact()进入Native层 ==> 由jni转到android_os_BinderProxy_transact()函数 ==> 调用IBinder->transact函数.

调用mRemote.transact时进到了BinderProxy并在其中调用native方法android_os_BinderProxy_transact()

直到jni为止的内容我们前面已经了解过了, 下面来看android_os_BinderProxy_transact()函数:

// in file frameworks/base/core/jni/android_util_Binder.cpp

......

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    // check and parse data
    ......

    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);// 获取mObject指向的本地对象

    status_t err = target->transact(code, *data, reply, flags);// 调用本地代码的transact

    if (err == NO_ERROR) {
        return JNI_TRUE;
    } else if (err == UNKNOWN_TRANSACTION) {
        return JNI_FALSE;
    }

    signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
    return JNI_FALSE;
}
......

static const JNINativeMethod gBinderProxyMethods[] = {
     /* name, signature, funcPtr */
    {"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},
    {"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},
    {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
    {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
    {"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
    {"destroy",             "()V", (void*)android_os_BinderProxy_destroy},
};
......

其中, gBinderProxyOffsets.mObject是在Java层调用IBinder.getContextObject()时, 在javaObjectForIBinder函数中设置的:

// in file frameworks/base/core/jni/android_util_Binder.cpp
......

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    return javaObjectForIBinder(env, b);
}

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    ...
    LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
    // The proxy holds a reference to the native object.
    env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());// 设置本地IBinder对象, 令mObject指向它
    val->incStrong((void*)javaObjectForIBinder);
    ...
}

.....
########################################################################

// in file frameworks/native/libs/binder/ProcessState.cpp
......

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    ...
    b = new BpBinder(handle);
    result = b;
    ...
    return result;
}

可见, android_os_BinderProxy_transact()函数实际上调用的是 BpBinder::transact() 函数.

jni中的target->transact调用进到BpBinder, 再进到IPCThreadState

来看看BpBinder::transact(), 它位于frameworks/native/libs/binder/BpBinder.cpp:

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);// 调用IPCThreadState::self()->transact
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

IPCThreadState中是这么写的:

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();

    flags |= TF_ACCEPT_FDS;

    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }

    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }

    return err;
}

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    binder_transaction_data tr;

    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;
    tr.code = code;
    ...

    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

由函数内容可以看出, 数据再一次通过 writeTransactionData() 传递给 mOut 进行写入操作. mOut 是一个 Parcel 对象, 声明在 IPCThreadState.h 文件中. 之后则调用 waitForResponse() 函数.

IPCThreadState::waitForResponse() 在一个 while 循环里不断的调用 talkWithDriver() 并检查是否有数据返回

// in file frameworks/base/libs/binder/IPCThreadState.cpp
......

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;

    while (1) { // 永真循环
        if ((err=talkWithDriver()) < NO_ERROR) break; // 调用talkWithDriver, 当返回负时退出循环
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;

        cmd = mIn.readInt32(); // 读取命令

        IF_LOG_COMMANDS() {
            alog << "Processing waitForResponse Command: "
                << getReturnString(cmd) << endl;
        }

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;

        case BR_DEAD_REPLY:
            err = DEAD_OBJECT;
            goto finish;

        case BR_FAILED_REPLY:
            err = FAILED_TRANSACTION;
            goto finish;

        case BR_ACQUIRE_RESULT:
            {
                LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            goto finish;

        case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));// 读取远端返回的数据
                LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;

                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t),
                            freeBuffer, this);
                    } else {
                        err = *static_cast<const status_t*>(tr.data.ptr.buffer);
                        freeBuffer(NULL,
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t), this);
                    }
                } else {
                    freeBuffer(NULL,
                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                        tr.offsets_size/sizeof(size_t), this);
                    continue;
                }
            }
            goto finish;

        default:
            err = executeCommand(cmd); // 处理其他命令, 例如NO_ERROR
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }

    return err;
}
......

IPCThreadState::talkWithDriver() 函数是真正与 binder 驱动交互的实现

......

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");

    binder_write_read bwr;

    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    // We don't want to write anything if we are still reading
    // from data left in the input buffer and the caller
    // has requested to read the next data.
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    // 写入数据
    bwr.write_size = outAvail;
    bwr.write_buffer = (long unsigned int)mOut.data();

    // This is what we'll read.
    // 读取数据
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (long unsigned int)mIn.data();
    } else {
        bwr.read_size = 0;
    }

    IF_LOG_COMMANDS() {
        TextOutput::Bundle _b(alog);
        if (outAvail != 0) {
            alog << "Sending commands to driver: " << indent;
            const void* cmds = (const void*)bwr.write_buffer;
            const void* end = ((const uint8_t*)cmds)+bwr.write_size;
            alog << HexDump(cmds, bwr.write_size) << endl;
            while (cmds < end) cmds = printCommand(alog, cmds);
            alog << dedent;
        }
        alog << "Size of receive buffer: " << bwr.read_size
            << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
    }

    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(HAVE_ANDROID_OS)
        // 使用系统调用 ioctl 向 /dev/binder 发送 BINDER_WRITE_READ 命令
        // 该过程在下一节详述
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        IF_LOG_COMMANDS() {
            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
        }
    } while (err == -EINTR);

    IF_LOG_COMMANDS() {
        alog << "Our err: " << (void*)err << ", write consumed: "
            << bwr.write_consumed << " (of " << mOut.dataSize()
            << "), read consumed: " << bwr.read_consumed << endl;
    }

    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < (ssize_t)mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        IF_LOG_COMMANDS() {
            TextOutput::Bundle _b(alog);
            alog << "Remaining data size: " << mOut.dataSize() << endl;
            alog << "Received commands from driver: " << indent;
            const void* cmds = mIn.data();
            const void* end = mIn.data() + mIn.dataSize();
            alog << HexDump(cmds, mIn.dataSize()) << endl;
            while (cmds < end) cmds = printReturnCommand(alog, cmds);
            alog << dedent;
        }
        return NO_ERROR;
    }

    return err;
}
......

ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) 就是使用系统调用函数 ioctlbinder 设备文件 /dev/binder 发送 BINDER_WRITE_READ 命令.
回到上一步waitForResponse, 获取到talkWithDriver返回的命令cmd后默认执行executeCommand(cmd), 来处理返回命令

IPCThreadState::executeCommand(int32_t cmd) 处理返回命令

除了在switch case中处理的命令以外, 其他的命令都通过调用executeCommand来处理, 它的实现如下:

......

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;

    switch (cmd) {
    // switch能处理的命令很多, 我们省略掉其他命令, 重点看正常数据处理
    ...
    case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            LOG_ASSERT(result == NO_ERROR,
                "Not enough command data for brTRANSACTION");
            if (result != NO_ERROR) break;

            Parcel buffer;
            buffer.ipcSetDataReference(
                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(size_t), freeBuffer, this);

            // 判断和设置优先级
            ...

            Parcel reply;
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);// 实际执行的是 BBinder.transact() !
                if (error < NO_ERROR) reply.setError(error);

            } else {
                const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);
            }

            if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                sendReply(reply, 0);
            } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
            }
            ...
        }
        break;
    ...
    return result;
}
......

可见它调用了BBinder::transact()来处理数据, 该函数定义如下:

// in file frameworks/base/libs/binder/Binder.cpp
status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);// 调用onTransact
            break;
    }

    if (reply != NULL) {
        reply->setDataPosition(0);
    }

    return err;
}

在此处b->transact调用时, b是一个JavaBBinder实例, JavaBBinder继承了BBinder类, 重写了onTransact, 所以这里实际调用的是JavaBBinder.onTransact, 定义见frameworks/base/core/jni/android_util_Binder.cpp:

virtual status_t onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
    JNIEnv* env = javavm_to_jnienv(mVM);
    ...
    jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
        code, (int32_t)&data, (int32_t)reply, flags);// 调用gBinderOffsets.mExecTransact
    ...
    return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}


static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz;

    clazz = env->FindClass(kBinderPathName);
    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Binder");
    ...
    gBinderOffsets.mExecTransact
        = env->GetMethodID(clazz, "execTransact", "(IIII)Z");
    ...
    return AndroidRuntime::registerNativeMethods(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}

由上可见, JavaBBinder通过JNI的gBinderOffsets.mExecTransact调用java方法android.os.Binder.execTransact. 执行的实际上是android.os.Binder.onTransact. 它的实现如下:

// in file frameworks/base/core/java/android/os/Binder.java

// Entry point from android_util_Binder.cpp's onTransact
private boolean execTransact(int code, int dataObj, int replyObj,
        int flags) {
    Parcel data = Parcel.obtain(dataObj);
    Parcel reply = Parcel.obtain(replyObj);
    // theoretically, we should call transact, which will call onTransact,
    // but all that does is rewind it, and we just got these from an IPC,
    // so we'll just call it directly.
    boolean res;
    try {
        res = onTransact(code, data, reply, flags);
    }
    // catch clauses
    ...
    reply.recycle();
    data.recycle();
    return res;
}

protected boolean onTransact(int code, Parcel data, Parcel reply,
       int flags) throws RemoteException {
   if (code == INTERFACE_TRANSACTION) {
       reply.writeString(getInterfaceDescriptor());
       return true;
   } else if (code == DUMP_TRANSACTION) {
       ParcelFileDescriptor fd = data.readFileDescriptor();
       String[] args = data.readStringArray();
       if (fd != null) {
           try {
               dump(fd.getFileDescriptor(), args);
           } finally {
               try {
                   fd.close();
               } catch (IOException e) {
                   // swallowed, not propagated back to the caller
               }
           }
       }
       // Write the StrictMode header.
       if (reply != null) {
           reply.writeNoException();
       } else {
           StrictMode.clearGatheredViolations();
       }
       return true;
   }
   return false;
}

由此可见, 经过Binder驱动之后, 最终会在服务端进程的android.os.Binder.onTransact处理命令和数据. 而我们在服务端的IYourService.Stub中, 重写了onTransact来调用服务接口的服务端实现(大多数情况下, 这个重写是aidl工具帮你完成的). 至此, Binder驱动下的IPC通讯过程已全部明了(除了中间处理进程状态的过程以及打开Binder设备文件进行数据读写的过程以外).

一句话总结就是: 客户端发送BC_TRANSACTION命令到Binder驱动->服务端进程监听BR_TRANSACTION命令并处理;如果是服务端返回数据, 过程类似, 但发送的命令是BC_REPLY命令->客户端监听BR_REPLY命令

Binder设备驱动实现

上一节中, 我们只简单提了一下ioctl系统调用是对/dev/binder设备文件进行读写操作, 这一节详述该过程.

首先, ioctl第一个参数mProcess->mDriverFD是Binder驱动的文件描述符(File Descriptor), 它是在ProcessState初始化时由函数open_driver()初始化的, open_driver代码如下:

// in file frameworks/base/libs/binder/ProcessState.cpp
static int open_driver()
{
    int fd = open("/dev/binder", O_RDWR);
    if (fd >= 0) {
        fcntl(fd, F_SETFD, FD_CLOEXEC);
        int vers;
        // 获取驱动版本
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result == -1) {
            LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
        // 检查驱动版本是否一致
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
            LOGE("Binder driver protocol does not match user space protocol!");
            close(fd);
            fd = -1;
        }
        // 设置最多15个线程
        size_t maxThreads = 15;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (result == -1) {
            LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
    }
    return fd;
}

初始化后文件描述符保存在mDriverFD中, 以后通过它就可以和设备文件交互.

其次, 在经过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)调用后, 对设备驱动文件的读写操作就被完全封装在了结构体binder_write_read中. 具体的读写过程见talkWithDriver的实现代码及我的注释.
可见, 真正的数据读写都是通过/dev/binder来执行的, 其上封了命令BINDER_WRITE_READ用一个数据结构binder_write_read来存储读取和写入的数据, 再上封了transact处理不同逻辑概念下的事务. 再上通过BBinder接口联系到JNI代码和Java代码.

最后, 让我们看看/dev/binder这个驱动程序的实现. 它是Binder的最终实现.
在看驱动代码前, 我们需要了解一些背景知识. 作为一个特殊的字符型设备, Binder的挂载节点是/dev/binder, 遵循Linux设备驱动模型, 在驱动实现过程中主要通过binder_ioctl函数与用户空间的进程交换数据. Android中的Service都是通过它来完成IPC的, 具体来说, 在Android虚拟机启动前, 系统会先启动ServiceManager进程, 它负责打开Binder驱动程序, 并告诉驱动程序自己将作为系统服务的管理者(通过特殊命令BINDER_SET_CONTEXT_MGR, 此后ServiceManager也通过Binder驱动与其他进程进行通讯), 然后ServiceManager进入循环, 等待处理来自其他进程的数据.
在Android系统中共有三种IPC机制:

  • 标准Linux Kernel IPC 接口
  • 标准D-BUS 接口
  • Binder接口

由于我没有了解过其他两种方式, 所以这里我就不评价孰优孰劣了, 在Android系统中大部分程序都使用了Binder接口. Binder是OpenBinder的精简实现, 包含一个Binder驱动程序, 一个Binder服务器, 一个Binder客户端.

清楚了以上背景之后, 让我们看一下Binder驱动程序的实现. Android中Binder协议的定义在头文件binder.h中, 不同版本源码的路径不太一样, 4.0的路径在external/kernel-headers/original/linux/binder.h, 定义了五种Binder类型(bhd分别表示binder handle FD三个大类):

enum {
    BINDER_TYPE_BINDER    = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
    BINDER_TYPE_WEAK_BINDER    = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
    BINDER_TYPE_HANDLE    = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
    BINDER_TYPE_WEAK_HANDLE    = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
    BINDER_TYPE_FD        = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};

同样是在这个头文件中, 定义了用于进程间传输的数据结构, 称作Binder Object, 它是一个flat_binder_object结构体, 定义如下(为方便理解我把注释也放上来了):

/*
 * This is the flattened representation of a Binder object for transfer
 * between processes.  The 'offsets' supplied as part of a binder transaction
 * contains offsets into the data where these structures occur.  The Binder
 * driver takes care of re-writing the structure type and data as it moves
 * between processes.
 */
struct flat_binder_object {
    /* 8 bytes for large_flat_header. */
    unsigned long        type;// Binder对象类型, 即前面Binder协议中五种类型的一种
    unsigned long        flags;// 传输方式, 见下面transaction_flags

    /* 8 bytes of data. */
    union {
        void        *binder;    /* local object */
        signed long    handle;        /* remote object */
    };

    /* extra data associated with local object */
    void            *cookie;
};

...
enum transaction_flags {
    TF_ONE_WAY    = 0x01,    /* this is a one-way call: async, no return */
    TF_ROOT_OBJECT    = 0x04,    /* contents are the component's root object */
    TF_STATUS_CODE    = 0x08,    /* contents are a 32-bit status code */
    TF_ACCEPT_FDS    = 0x10,    /* allow replies with file descriptors */
};

从注释可以知道, flat_binder_object中的union结构存的就是要传输的数据, 当类型为Binder时, 数据是一个本地对象*binder, 当类型为Handle时, 数据是一个远程对象handle. Binder对象在进程间传递时, Binder驱动会修改它的类型和数据.
正如Binder的客户端和服务端是相对而言的一样, 这里的本地Binder和远程Handle对象也是相对而言的, 其实他们都指向同一个对象, 所以他们共用一个union空间, 只不过A的本地对象binder对于另一进程B来说就是远程对象handle.

虽然flat_binder_object是要传输的Binder对象, 但实际上Binder驱动并不直接操作它, 而是将它封装成了一个binder_transaction_data, 操作的直接对象是这个封装的数据. 该封装的定义如下:

struct binder_transaction_data {
    /* The first two are only used for bcTRANSACTION and brTRANSACTION,
     * identifying the target and contents of the transaction.
     */
    union {
        size_t    handle;    /* target descriptor of command transaction */
        void    *ptr;    /* target descriptor of return transaction */
    } target;
    void        *cookie;    /* target object cookie */
    unsigned int    code;        /* transaction command */

    /* General information about the transaction. */
    unsigned int    flags;
    pid_t        sender_pid;
    uid_t        sender_euid;
    size_t        data_size;    /* number of bytes of data */
    size_t        offsets_size;    /* number of bytes of offsets */

    /* If this transaction is inline, the data immediately
     * follows here; otherwise, it ends with a pointer to
     * the data buffer.
     */
    union {
        struct {
            /* transaction data */
            const void    *buffer;// flat_binder_object被封装在*buffer中
            /* offsets from buffer to flat_binder_object structs */
            const void    *offsets;
        } ptr;
        uint8_t    buf[8];
    } data;
};



了解了真正传输的数据结构之后, 让我们来深入Binder生命周期. 以下内容涉及到: Binder设备创建, Binder启动, Binder释放, Binder数据关联, Binder接口及命令含义. 我尽量从我自己追踪代码的习惯来讲解, 这样虽然效率比较低但是好处是更容易理解和回忆. 以下内容与源码实现紧密关联, 再次声明, 本文基于Android4.0源码写就, 不适用于其他版本.

  1. Binder设备创建
    作为一个特殊的符号设备, Binder设备也是需要进行创建的. 可以合理猜测系统有一个统一的创建驱动设备的过程, Binder作为其中一个设备一起被创建(如果不对, 就追踪调用栈, 看哪里引用了frameworks/base/cmds/servicemanager/binder.c, 特别是调用了里面的binder_open). 在这种猜测下, 我们来找一下符号设备的创建(我假设你跟我一样不知道Android下启动过程是否跟Linux一样). 到源码目录搜索/dev/binder, 除了前面提到的ProcessState.open_driver以外, 在以下三个文件中还出现了/dev/binder: frameworks/base/cmds/servicemanager/binder.c, system/core/rootdir/ueventd.rc, system/extras/tests/fstest/perm_checker.conf. 好像没有看出哪个是创建binder设备? 别急, 如果你看过老罗的<在Ubuntu上为Android系统编写Linux内核驱动程序>一文, 就可能猜测, 在文件frameworks/base/cmds/servicemanager/binder.c中, 有完整的binder_open binder_release binder_write实现, 正好这三个操作是实现Linux设备驱动时需要定义的基本操作的一部分, 这意味着该文件很可能就是Binder设备驱动文件. 我们假设它的确是, 那么应该有设备注册和初始化操作(模块加载, 卸载方法), 但很遗憾搜索之后发现没有. 难道Binder设备不用注册吗? 不是的, 进一步在整个源码范围搜索binder注册函数binder_init, 发现它匹配到了prebuilt/android-arm/kernel/vmlinux-qemu, 而这个我们知道是预编译好的Linux内核, 看来应该是在Linux内核源码里实现的设备注册, 遗憾的是直接下载Android源码的话是不带内核源码的, 我只好去下载了对应的内核源码(4.0系统对应3.0内核, 2.2系统对应2.6内核, 4.2~4.3系统对应3.4内核). 本文不讲怎么下载Android内核代码, 直接给出相关代码片段:

    // in file kernel/goldfish/drivers/staging/android/binder.c
    
    // 定义文件操作函数
    static const struct file_operations binder_fops = {
        .owner = THIS_MODULE,
        .poll = binder_poll,
        .unlocked_ioctl = binder_ioctl,
        .mmap = binder_mmap,
        .open = binder_open,
        .flush = binder_flush,
        .release = binder_release,
    };
    
    static struct workqueue_struct *binder_deferred_workqueue;
    
    // 初始化函数
    static int __init binder_init(void)
    {
        int ret;
    
        // 创建了一个内核工作队列对象workqueue, 用于执行可以延期执行的工作任务
        binder_deferred_workqueue = create_singlethread_workqueue("binder");
        if (!binder_deferred_workqueue)
            return -ENOMEM;
    
        // 创建调试目录 /sys/kernel/debug/binder
        binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
        if (binder_debugfs_dir_entry_root)
            binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
                             binder_debugfs_dir_entry_root);
        // 注册字符设备
        ret = misc_register(&binder_miscdev);
        // 创建调试文件
        if (binder_debugfs_dir_entry_root) {
            debugfs_create_file("state",
                        S_IRUGO,
                        binder_debugfs_dir_entry_root,
                        NULL,
                        &binder_state_fops);
                        ...
        }
        return ret;
    }
    
    // 调用初始化函数加载内核, 基本等价于不支持动态编译驱动模块的module_init, 如果需要把Binder改成动态的内核模块, 直接把这个device_initcall改成module_init, 同时添加驱动卸载接口函数 module_exit即可
    device_initcall(binder_init);
    

    可见在系统装载设备的时候, 就加载了Binder设备模块, 并绑定了设备操作对应的函数.

    好奇心重一点的读者可能会去自行发掘Linux设备模块怎么编写. Linux驱动程序的一个主要功能就是向用户空间的程序提供操作接口, 这个接口是标准的, Binder包含的接口有:

    -Proc接口(/proc/binder)
        . /proc/binder/state
        . /proc/binder/stats
        . /proc/binder/transactions
        . /proc/binder/transaction_log
        . /proc/binder/failed_transaction_log
        . /proc/binder/proc/
    
    -设备接口(/dev/binder)
        . binder_open
        . binder_release
        . binder_flush
        . binder_mmap
        . binder_poll
        . binder_ioctl
    
  2. Binder启动
    frameworks/base/cmds/servicemanager/binder.c中定义了binder设备打开的函数binder_open:

    struct binder_state *binder_open(unsigned mapsize)
    {
        struct binder_state *bs;
    
        bs = malloc(sizeof(*bs));
        if (!bs) {
            errno = ENOMEM;
            return 0;
        }
    
        bs->fd = open("/dev/binder", O_RDWR);
        if (bs->fd < 0) {
            fprintf(stderr,"binder: cannot open device (%s)\n",
                    strerror(errno));
            goto fail_open;
        }
    
        bs->mapsize = mapsize;
        bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
        if (bs->mapped == MAP_FAILED) {
            fprintf(stderr,"binder: cannot map device (%s)\n",
                    strerror(errno));
            goto fail_map;
        }
    
            /* TODO: check version */
    
        return bs;
    
    fail_map:
        close(bs->fd);
    fail_open:
        free(bs);
        return 0;
    }
    

    这个函数作用是把设备映射到内存, 在Binder设备驱动中还有一个同名函数负责打开Binder设备和设置引用计数, 如下:

    // in file kernel/goldfish/drivers/staging/android/binder.c
    
    static int binder_open(struct inode *nodp, struct file *filp)
    {
        struct binder_proc *proc;
    
        // 初始化, 分配 binder_proc 数据结构内存
        proc = kzalloc(sizeof(*proc), GFP_KERNEL);
        if (proc == NULL)
            return -ENOMEM;
    
        // 增加当前线程/进程的引用计数并赋值给proc->tsk
        get_task_struct(current);
        proc->tsk = current;
        // 初始化binder_proc队列和默认优先级
        INIT_LIST_HEAD(&proc->todo);
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
    
        binder_lock(__func__);
    
        // 增加 BINDER_STAT_PROC对象计数
        binder_stats_created(BINDER_STAT_PROC);
        // 添加进程节点proc_node到binder_procs的全局列表中, 任何进程都可以访问其他进程的binder_proc对象
        hlist_add_head(&proc->proc_node, &binder_procs);
        // 保存进程id
        proc->pid = current->group_leader->pid;
        INIT_LIST_HEAD(&proc->delivered_death);
        // 驱动文件的private_data指向proc
        filp->private_data = proc;
    
        binder_unlock(__func__);
        ...
    
        return 0;
    }
    
  3. Binder释放
    同样是在frameworks/base/cmds/servicemanager/binder.c文件中定义了设备释放函数binder_release:

    void binder_release(struct binder_state *bs, void *ptr)
    {
        uint32_t cmd[2];
        cmd[0] = BC_RELEASE;
        cmd[1] = (uint32_t) ptr;
        binder_write(bs, cmd, sizeof(cmd));
    }
    

    可见只是发送了一个释放命令给Binder驱动, 那么可以肯定驱动中也有一个释放函数, 正好前面看到过设备操作的接口中有一个就是binder_release与这里的函数同名, 不会是巧合. kernel/goldfish/drivers/staging/android/binder.c中相关代码片段如下:

    static int binder_release(struct inode *nodp, struct file *filp)
    {
        struct binder_proc *proc = filp->private_data;
        debugfs_remove(proc->debugfs_entry);
        binder_defer_work(proc, BINDER_DEFERRED_RELEASE);
    
        return 0;
    }
    

    好嘛, 释放操作给了binder_defer_work, 这又是嘛? 其实前面我们在初始化的时候就有内容涉及到它: 在create_singlethread_workqueue的时候创建了一个叫做binder_deferred_workqueue的队列, 该队列用来调度执行binder_deferred_work, 而两者发生联系就是在函数binder_defer_work中, queue_work使用了他们作为函数参数. 前面说过这个队列里都是可以延期执行的任务, 而binder_deferred_work有三种类型, 即枚举变量binder_deferred_state中定义的PUT_FILES FLUSH RELEASE.
    显然, 释放的具体操作就要看queue_work函数了, 很可惜我查的资料里没有详述这个函数做了啥. 它的定义在kernel/goldfish/kernel/workqueue.c中, 粗略看了下, 理解不一定对, 感觉它跟Handler类似, 在入队work的时候获取执行work的worker, 而由别的过程控制出队和实际执行, 只不过它所处的层次更靠近硬件.

  4. Binder数据关联
    前面说过, 传输对象中binderhandle其实指向的是同一个对象, 现在来解释一下为什么. 在一次调用中, 对于客户端进程来说, handle存储的索引是一个远端对象的句柄, 当数据经由Binder驱动传达到服务端的时候, 服务端就会把这个索引解释为本地对象的地址, 对于第三方来说, 客户端的handle和服务端的binder都是指向了服务端的那个Binder对象. 对于Binder来说, 对象的索引和映射是通过binder_nodebinder_ref两个核心数据结构来完成的, 两个定义都可以在文件kernel/goldfish/drivers/staging/android/binder.c中看到. 对于Binder本地对象, 对象的Binder地址保存在binder_node->ptr里, 对于远程对象, 索引保存在binder_ref->desc里, 每一个binder_node都有一个binder_ref与之对应, 他们通过ptrdesc来做映射. 前面说过进程间传递的Binder对象实际上是flat_binder_object这个数据结构, 每个flat_binder_object在内核都有一个唯一的binder_node对象与之对应, 这个对象挂载在binder_proc的一棵二叉树上, 而每一个binder_node又有唯一一个binder_ref对象与之对应. 可以这么理解, binder_ref->desc binder_node->ptr binder_node->cookie flat_binder_object->handle四者都指向同一个对象, 其中binder_node->ptr binder_node->cookiebinder_node位于服务端. binder_ref按照node和desc两种方式映射到binder_proc对象上, 因此可以通过binder_node或者desc查找到binder_refbinder_node. 对于一个flat_binder_object对象来说, 它的binder, cookie, handle都指向的同一个binder_node对象.
    Binder驱动中, flush操作在关闭一个设备文件描述符拷贝时被调用, 这里不做探究. 另一个操作mmap(memory map)负责把设备内存映射到用户进程地址空间中, 用户进程可以像操作内存一样操作设备. 一般的设备驱动, 设备内存是设备本身具有的, 或者在驱动初始化时由vmallockmalloc等内核函数分配好, Binder不同于此, 它的设备内存是由mmap操作来分配的, 分配方法是现在内核虚拟映射表上获取一段可用区域, 再分配物理页, 并把物理页映射到获取的虚拟地址区域. 每个进程/线程只能做一次mmap操作, 其后重复操作都会返回错误. mmap分配内存的代码见文件kernel/goldfish/drivers/staging/android/binder.c#binder_mmap片段, 过程大致是先做检查调用合法性等准备工作, 然后申请虚拟内存空间, 再使用binder_update_page_range分配物理空间(实际是分配了1个页的物理内存用来存储指针buffer, 1个物理页是4K, 1个指针是4字节, 所以1页最多可存1K个指针, 每个指针对应一个物理页, 所以对应最多4M物理空间, 这是一次mmap最多可以分配的物理内存量, 这里不管实际申请了多大的物理内存, 内核总是提供1页物理内存用来放buffer指针, 即每次都允许申请最多的物理页), 在该函数中利用Linux系统中内存相关函数完成具体分配任务, 完成后由binder_buffer负责管理该内存区域, binder_buffer放到了proc->buffers链表中, 今后就可以通过这段内存区域完成设备数据读写了. 更形象的插图见深入分析Android Binder 驱动相关章节, 本段主要参考该文和内核代码完成.
  5. Binder接口及命令
    Binder能得以正确工作, 首先要依赖于一致的Binder协议. 其中Binder类型在前文external/kernel-headers/original/linux/binder.h中提到过, 一共3大类5小类. 其实该文件中还定义了Binder驱动支持的命令格式和数据定义, 分为客户端的BinderDriverCommandProtocol和服务端的BinderDriverReturnProtocol, 两个都是枚举类型, 很可惜以我现在的C水平, 看不懂枚举成员BC_TRANSACTION = _IOW_BAD('c', 0, struct binder_transaction_data)的写法是什么意思, 大概猜测是第一个参数是访问模式, 第二个参数是指令, 第三个参数是数据指针. 客户端命令(BC)中第一个参数都是’c’, 宏_IOR_BAD根据资料应该是指向的ioctl的, 也就是说这里的参数传给了ioctl. 服务端返回(BR)的第一个参数都是’r’, 表示read. 两个数据结构定义了Binder客户端和服务端可以执行的全部命令. 既然有协议, 自然就有版本, 细心的读者可能发现, 前文binder_open函数里面就隐藏了一段注释, 说明以后会有check version的步骤.

本节主要参考:

结语

给两个主要结论和一个图(图不是我画的, 但来源记不得了), 方便大家按图索骥.

binder native stack

  1. Binder的实现从上到下涉及到Java层(Application层)/JNI层/Native层(Runtime层)/Linux kernel层, 可以说涉及到了Android的整个架构, 说是它的核心之一一点不过分. 系统服务的注册/获取/使用/Intent传递都通过Binder驱动, 对它的深入理解将会起到提纲挈领的效果.

  2. 上层的android.os.Binder是对Binder的一层封装, 一般不直接使用. 如果定义服务, 使用系统提供的Service接口即可(它完成了一个默认的android.os.Binder实现), 如果是自定义跨进程服务, 使用AIDL将是更快的方式, 它本质是一个对Binder操作进行封装的工具. 如果不嫌麻烦, 直接使用android.os.Binder来定义客户端和服务端也是完全可行的.

说实话这篇文章写得有点吃力, 一个是时间拉太长, 记忆跟不上, 另一个是这个内容本身比较难用平白的语言讲清楚. 感谢大家阅读, 难免理解有误或以讹传讹, 欢迎大家指正.

文章目录
  1. 1. 某渣的凭印象回(hu)顾(zhou)
  2. 2. Binder的设计思想/工作原理
  3. 3. Binder实践
    1. 3.1. Service的启动过程
    2. 3.2. Binder驱动的实现
      1. 3.2.1. 调用mRemote.transact时进到了BinderProxy并在其中调用native方法android_os_BinderProxy_transact()
      2. 3.2.2. jni中的target->transact调用进到BpBinder, 再进到IPCThreadState
      3. 3.2.3. IPCThreadState::waitForResponse() 在一个 while 循环里不断的调用 talkWithDriver() 并检查是否有数据返回
      4. 3.2.4. IPCThreadState::talkWithDriver() 函数是真正与 binder 驱动交互的实现
      5. 3.2.5. IPCThreadState::executeCommand(int32_t cmd) 处理返回命令
      6. 3.2.6. Binder设备驱动实现
  4. 4. 结语